#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include "thread_pool.hpp"
#include "task.hpp"

using namespace ns_thread_pool;
using namespace NSTask;

#define NUM 1024

void Usage(char *args)
{
    std::cout << "Usage :" << args << " server_port" << std::endl;
}

void ServiceIO(int new_sock)
{
    char buf[NUM] = {0};

    // while (true)
    // {
    bzero(buf, NUM);
    ssize_t sz = read(new_sock, buf, NUM - 1);

    if (sz > 0)
    {
        buf[sz] = 0;

        std::cout << "client# " << buf << std::endl;

        std::string s;

        s += ">>server<< ";
        s += buf;

        write(new_sock, s.c_str(), s.size());
    }
    else if (sz == 0)
    {
        std::cout << "client quit" << std::endl;
        // break;
    }
    else
    {
        std::cerr << "read error" << std::endl;
        // break;
    }
    // }
}

void* handler(void* psock)
{
    pthread_detach(pthread_self());
    int sock = *(int*)psock;
    delete (int*)psock;

    ServiceIO(sock);
    close(sock);

    // 线程直接使用exit会将进程全部退出
    // exit(0);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    // 1. 创建套接字
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        std::cerr << "sock failed : " << errno << std::endl;
        return 2;
    }

    uint16_t port = atoi(argv[1]);

    // 2. bind
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(port);
    local.sin_addr.s_addr = INADDR_ANY;

    if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0)
    {
        std::cerr << "bind failed : " << errno << std::endl;
        return 3;
    }

    const int backlog = 5;
    // 3. 设置套接字为listen状态
    if (listen(sock, backlog) < 0)
    {
        std::cerr << "listen set failed : " << errno << std::endl;
        return 4;
    }

    // 让子进程自动释放
    // signal(SIGCHLD, SIG_IGN);

    // 4. 接受连接，提供服务
    while (true)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);

        int new_sock = accept(sock, (struct sockaddr *)&peer, &len); // peer返回连接的客户端的信息
        if (new_sock < 0)
        {
            continue;
        }
        uint16_t ClientPort = ntohs(peer.sin_port);
        std::string ClientIp = inet_ntoa(peer.sin_addr);// 将ip转换为点分十进制形式
        std::cout << "connecting succeed!——" << new_sock << "——"<<ClientIp << ":" << ClientPort <<  std::endl;

        // version4 ：线程池
        task t(new_sock);
        ThreadPool<task>::GetInstance()->Push(t);
        

        // version3 ：多线程
        // 线程之间文件描述符共享
        // pthread_t tid;
        // int* argument = new int(new_sock);
        // pthread_create(&tid, nullptr, handler, (void*)argument);

        // // version1 ：创建子进程
        // // version1.1 ：孙子进程运行业务逻辑
        // pid_t id = fork();

        // if (id == 0)
        // {
        //     // 子进程会继承父进程的文件描述符，所以先关闭监听套接字
        //     close(sock);

        //     // 子进程再创建一个孙子进程，然后自己退出，这时孙子进程继续执行下面逻辑
        //     // 最后会被守护进程收养，不用通过信号实现资源回收
        //     if(fork() > 0) 
        //         exit(0);
        //     ServiceIO(new_sock);
        //     close(new_sock);// 打开new_sock后关闭
        //     exit(0);
        // }
        // else if (id > 0)
        // {
        //     // 关闭new_sock
        //     waitpid(id, nullptr, 0);
        //     close(new_sock);
        // }
        // else
        // {
        //     std::cerr << "fork error" << std::endl;
        //     continue;
        // }
    }

    return 0;
}